/*
Copyright 2024 New Vector Ltd.
Copyright 2017 Vector Creations Ltd

SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
 */

#import "MXKCountryPickerViewController.h"

@import libPhoneNumber_iOS;

#import "NSBundle+MatrixKit.h"
#import "MXKSwiftHeader.h"


NSString* const kMXKCountryPickerViewControllerCountryCellId = @"kMXKCountryPickerViewControllerCountryCellId";

@interface MXKCountryPickerViewController ()
{
    NSMutableDictionary<NSString*, NSString*> *isoCountryCodesByCountryName;
    
    NSArray<NSString*> *countryNames;
    NSMutableArray<NSString*> *filteredCountryNames;
    
    NSString *previousSearchPattern;
    
    NSMutableDictionary<NSString*, NSNumber*> *callingCodesByCountryName;
}

@end

@implementation MXKCountryPickerViewController

#pragma mark - Class methods

+ (UINib *)nib
{
    return [UINib nibWithNibName:NSStringFromClass([MXKCountryPickerViewController class])
                          bundle:[NSBundle bundleForClass:[MXKCountryPickerViewController class]]];
}

+ (instancetype)countryPickerViewController
{
    return [[[self class] alloc] initWithNibName:NSStringFromClass([MXKCountryPickerViewController class])
                                          bundle:[NSBundle bundleForClass:[MXKCountryPickerViewController class]]];
}

- (void)finalizeInit
{
    [super finalizeInit];
    
    NSArray *isoCountryCodes = [NSLocale ISOCountryCodes];
    NSMutableArray<NSString*> *countries;
    
    isoCountryCodesByCountryName = [NSMutableDictionary dictionaryWithCapacity:isoCountryCodes.count];
    countries = [NSMutableArray arrayWithCapacity:isoCountryCodes.count];
    
    NSLocale *local = [[NSLocale alloc] initWithLocaleIdentifier:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0]];
    
    for (NSString *isoCountryCode in isoCountryCodes)
    {
        NSString *country = [local displayNameForKey:NSLocaleCountryCode value:isoCountryCode];
        if (country)
        {
            [countries addObject: country];
            isoCountryCodesByCountryName[country] = isoCountryCode;
        }
    }
    
    countryNames = [countries sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
    
    previousSearchPattern = nil;
    filteredCountryNames = nil;
    
    _showCountryCallingCode = NO;
}

- (void)destroy
{
    [super destroy];
    
    isoCountryCodesByCountryName = nil;
    
    countryNames = nil;
    filteredCountryNames = nil;
    
    callingCodesByCountryName = nil;
    
    previousSearchPattern = nil;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // Check whether the view controller has been pushed via storyboard
    if (!self.tableView)
    {
        // Instantiate view controller objects
        [[[self class] nib] instantiateWithOwner:self options:nil];
    }
    
    self.navigationItem.title = [VectorL10n countryPickerTitle];
    
    [self setupSearchController];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    
    self.navigationItem.hidesSearchBarWhenScrolling = YES;
}

#pragma mark - 

- (void)setShowCountryCallingCode:(BOOL)showCountryCallingCode
{
    if (_showCountryCallingCode != showCountryCallingCode)
    {
        _showCountryCallingCode = showCountryCallingCode;
        
        if (_showCountryCallingCode && !callingCodesByCountryName)
        {
            callingCodesByCountryName = [NSMutableDictionary dictionary];
            
            for (NSString *countryName in countryNames)
            {
                NSString *isoCountryCode = isoCountryCodesByCountryName[countryName];
                NSNumber *callingCode = [[NBPhoneNumberUtil sharedInstance] getCountryCodeForRegion:isoCountryCode];
                
                callingCodesByCountryName[countryName] = callingCode;
            }
        }
        
        [self.tableView reloadData];
    }
}

#pragma mark - Private

- (void)setupSearchController
{
    UISearchController *searchController = [[UISearchController alloc]
     initWithSearchResultsController:nil];
    searchController.obscuresBackgroundDuringPresentation = NO;
    searchController.hidesNavigationBarDuringPresentation = NO;
    searchController.searchResultsUpdater = self;
    
    self.navigationItem.searchController = searchController;
    // Make the search bar visible on first view appearance
    self.navigationItem.hidesSearchBarWhenScrolling = NO;
    
    self.definesPresentationContext = YES;
    
    self.searchController = searchController;
}

#pragma mark - UITableView dataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (filteredCountryNames)
    {
        return filteredCountryNames.count;
    }
    return countryNames.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:kMXKCountryPickerViewControllerCountryCellId];
    if (!cell)
    {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kMXKCountryPickerViewControllerCountryCellId];
    }
    
    NSInteger index = indexPath.row;
    NSString *countryName;
    
    if (filteredCountryNames)
    {
        if (index < filteredCountryNames.count)
        {
            countryName = filteredCountryNames[index];
        }
    }
    else if (index < countryNames.count)
    {
        countryName = countryNames[index];
    }
    
    if (countryName)
    {
        cell.textLabel.text = countryName;
        
        if (self.showCountryCallingCode)
        {
            cell.detailTextLabel.text = [NSString stringWithFormat:@"+%@", [callingCodesByCountryName[countryName] stringValue]];
        }
    }
    
    return cell;
}

#pragma mark - UITableView delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    
    if (self.delegate)
    {
        NSInteger index = indexPath.row;
        NSString *countryName;
        
        if (filteredCountryNames)
        {
            if (index < filteredCountryNames.count)
            {
                countryName = filteredCountryNames[index];
            }
        }
        else if (index < countryNames.count)
        {
            countryName = countryNames[index];
        }
        
        if (countryName)
        {
            NSString *isoCountryCode = isoCountryCodesByCountryName[countryName];
            
            [self.delegate countryPickerViewController:self didSelectCountry:isoCountryCode];
        }
    }
}

#pragma mark - UISearchResultsUpdating

- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
    NSString *searchText = searchController.searchBar.text;
    
    if (searchText.length)
    {
        searchText = [searchText lowercaseString];
        
        if (previousSearchPattern && [searchText hasPrefix:previousSearchPattern])
        {
            for (NSUInteger index = 0; index < filteredCountryNames.count;)
            {
                NSString *countryName = [filteredCountryNames[index] lowercaseString];
                
                if ([countryName hasPrefix:searchText] == NO)
                {
                    [filteredCountryNames removeObjectAtIndex:index];
                }
                else
                {
                    index++;
                }
            }
        }
        else
        {
            filteredCountryNames = [NSMutableArray array];
            
            for (NSUInteger index = 0; index < countryNames.count; index++)
            {
                NSString *countryName = [countryNames[index] lowercaseString];
                
                if ([countryName hasPrefix:searchText])
                {
                    [filteredCountryNames addObject:countryNames[index]];
                }
            }
        }
        
        previousSearchPattern = searchText;
    }
    else
    {
        previousSearchPattern = nil;
        filteredCountryNames = nil;
    }
    
    [self.tableView reloadData];
}

@end
